package com.zkh.myutils.json;

import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import com.zkh.myutils.annotation.Format;
import com.zkh.myutils.annotation.Ignore;
import com.zkh.myutils.bean.BeanBaseTypeConverter;
import com.zkh.myutils.bean.TypeConverter;
import com.zkh.myutils.bean.TypeConverterItem;
import com.zkh.myutils.io.log.Logger;
import com.zkh.myutils.utils.DateUtils;
import com.zkh.myutils.utils.StringUtils;

/**
 * JSON 对象解析器
 * @author zkh
 */
public final class JSONObjectParser {
	//转换器
	TypeConverter converter;
	
	/**
	 * 解析器构造方法
	 */
	JSONObjectParser(TypeConverter converter){
		this.converter = converter;
	}

	/**
	 * 解析对象为Map集合（obj为已过滤的可解析的对象）
	 * @return
	 */
	@SuppressWarnings({"rawtypes", "unchecked"})
	Map<String, Object> parseToMap(Object obj){
		//Map容器
		Map<String, Object> map = new LinkedHashMap<String, Object>();
		//Class
		Class<?> cls = obj.getClass();
		//加载到顶级父类
		while(cls!=null  && !"java.lang.Object".equals(cls.getName())) {
			//开始解析
			for(Field field: cls.getDeclaredFields()) {
				//忽略字段
				if(field.isAnnotationPresent(Ignore.class)) {
					continue;
				}
				//字段类型
				Class<?> type = field.getType();String typeName = type.getSimpleName();
				//字段名
				String fn = field.getName(),ucfirst = StringUtils.uppercaseFirst(fn);
				//Getter
				String getterName = "get" + ucfirst, isGetter = "is" + ucfirst;
				//getter方法
				Method getter = null;
				//获取getter
				try {
					getter = cls.getMethod(getterName);
				} catch (NoSuchMethodException | SecurityException e1) {
					if("Boolean".equals(typeName) || "boolean".equals(typeName)) {
						try {
							getter = cls.getMethod(isGetter);
						} catch (NoSuchMethodException | SecurityException e) {
							//没有getter
						}
					}
				}
				//有getter
				if(getter!=null) {
					//解析
					try {
						//获取值
						Object curr = getter.invoke(obj);
						//值的class
						Class<?> currClass = curr==null ? null : curr.getClass();
						//用户自定义解析器
						TypeConverterItem converterItem = converter.getConverter(currClass);
						//为空，直接保存
						if(curr==null) {
							map.put(fn, curr);
						}
						//检测到类型存在用户自定义转换器
						else if(converterItem!=null) {
							map.put(fn, converterItem.convertToTarget(curr));
						}
						//为基础类型、为字符串，直接保存
						else if(BeanBaseTypeConverter.notParseType.contains(typeName) || "String".equals(typeName)) {
							map.put(fn, curr);
						}
						//日期类型
						else if(curr instanceof Date) {
							//默认解析格式
							String pattern = "yyyy-MM-dd HH:mm:ss";
							//获取是否有注解
							Format fmt = field.getAnnotation(Format.class);
							//有注解
							if(fmt!=null) {
								pattern = fmt.pattern();
							}
							//解析并保存
							map.put(fn, DateUtils.getString((Date) curr, pattern));
							
						}
						//集合或数组
						else if(curr instanceof Collection || currClass.isArray()) {
							map.put(fn, parseToList(curr));
						}
						else if(curr instanceof Map) {
							map.put(fn, parseMap(curr));
						}
						//可解析对象
						else {
							map.put(fn, parseToMap(curr));
						}
					} catch (IllegalArgumentException | IllegalAccessException | InvocationTargetException e) {
						Logger.error(e);
					}
				}
			}
			//获取父类
			cls = cls.getSuperclass();
		}
		//返回解析后的数据
		return map;
	}
	
	/**
	 * 解析数组和集合为List集合
	 * @return
	 */
	List<Object> parseToList(Object obj){
		//集合容器
		List<Object> ctn = new ArrayList<Object>();
		//数组
		if(obj.getClass().isArray()) {
			//遍历数组
			for(int i=0,len=Array.getLength(obj); i<len; i++) {
				//当前值
				Object curr = Array.get(obj, i);
				//进一步解析curr的类型
				ctn.add(parseObject(curr));
			}
		}else {
			//遍历集合数据
			for(Object curr: (Collection<?>) obj) {
				//进一步解析curr的类型
				ctn.add(parseObject(curr));
			}
		}
		return ctn;
	}
	
	/**
	 * 解析Object。此处的Object为未知类型，需要解析
	 * @param obj 待解析的Object
	 */
	@SuppressWarnings({"unchecked", "rawtypes"})
	public Object parseObject(Object obj) {
		//Class
		Class<?> cls = null;
		//用户自定义解析器
		TypeConverterItem itemConverter = converter.getConverter(cls);
		//为空判断
		if(obj==null) {
			return obj;
		}
		//自定义解析器
		else if(itemConverter!=null) {
			return itemConverter.convertToTarget(obj);
		}
		//字符串
		else if(obj instanceof String) {
			return obj;
		}//日期类型
		else if(obj instanceof Date) {
			//返回年月日时分秒
			return DateUtils.getString((Date) obj, "yyyy-MM-dd HH:mm:ss");
		}
		//基础类型，不用再解析
		else if(BeanBaseTypeConverter.notParseType.contains((cls = obj.getClass()).getSimpleName())) {
			return obj;
		}
		//嵌套集合数组
		else if(obj instanceof Collection || cls.isArray()){
			return parseToList(obj);
		}else if(obj instanceof Map){
			//转换后的Map
			return parseMap(obj);
		}else{
			//对象，逐个属性解析
			return parseToMap(obj);
		}
	}
	
	/**
	 * 解析Map，key不能是Map
	 * @param obj 指定Map对象
	 */
	@SuppressWarnings({"unchecked", "rawtypes"})
	private Map<String, Object> parseMap(Object obj) {
		//转换后的Map
		Map<String, Object> tmap = new LinkedHashMap<String, Object>();
		//遍历Map
		((Map) obj).forEach((k, v)->{
			//转换后的值
			String key = null;
			/* *******************   处理key  ******************/
			//key不能为null
			if(k==null) {
				throw new JSONParseException("Map的key不能为空");
			}
			//用户自定义解析器
			TypeConverterItem keyConverter = converter.getConverter(k.getClass());
			//字符串，直接取
			if(k instanceof String) {
				key = k.toString();
			}
			//自定义解析
			else if(keyConverter!=null) {
				//转换值
				Object tkey = keyConverter.convertToTarget(obj);
				//值
				key = tkey==null ? null : tkey.toString();
			}
			//日期类
			else if(obj instanceof Date) {
				//返回年月日时分秒
				key = DateUtils.getString((Date) obj, "yyyy-MM-dd HH:mm:ss");
			}
			//其它类型直接toString
			else {
				key = k.toString();
			}
			//检查空
			if(StringUtils.isEmpty(key)) {
				throw new JSONParseException("Map的key不能为空");
			}
			//保存
			tmap.put(key, parseObject(v));
		});
		//返回
		return tmap;
	}
}
